本篇銜接上篇:https://ithelp.ithome.com.tw/articles/10272738
今天來深入聊聊怎麼調節動畫模式的隨機性
今天由四個部分組成,來作循序漸進的思考:
讓我們用 今天的演示 來感受一下
為了沒看過前面19篇的朋友們簡述一下步驟
- 點選「上傳音樂」或「請選擇曲名」來換一首歌
- 點選「Play」進行播放,點選「Pause」暫停
- 選擇不同模式感受動畫的變化
如果試著用昨天的代碼去跑動畫,就會發現它看起來相當規律
什麼意思呢?當時的角速度預設為定值,那每個物件的簡諧運動就很單純:
this.rotateOmega = 60 / 180 * Math.PI;
this.revolveOmega = 60 / 180 * Math.PI;
那如果我單純把60這個數字改成隨機的40~80之間行不行?這個問題留給大家思考答案,並想看看為什麼,歡迎留言表達觀點。
當角速度是定值時,就會發現動畫的路徑相當規律,可以很容易地透過觀察發現,每一個物件基本相同,更可以輕鬆預測動畫的走向,顯得呆版、無聊,卻可以減少使用者的負荷,更加輕鬆、具有一致性,很適合用在簡單的關卡,當你更重視注重情節而非挑戰性,規律顯然是最舒適的
昨天我們寫了一個隨機數:this.period = 1 + Math.random() * 1;
,但還沒真正拿來用,而之所以設定period的理由,其實是希望簡諧運動搖擺的幅度有大有小,假如週期不變,則幅度越大時移動速度越快,這樣就會變得相當奇怪(可以想像擺福是整個螢幕的寬度,然後在3秒間來回擺動),因此在擺福增加的時候也同時讓週期增加,這就是設定一個介於1~2之間的period之用意。
因此角速度除以period以後:
this.rotateOmega = 60 / this.period / 180 * Math.PI;
this.revolveOmega = 60 / this.period / 180 * Math.PI;
去把對應的擺福乘上period:
this.pointX = this.beginX + this.period * WIDTH * 0.04 * A + WIDTH * 0.02 * dT;
this.pointY = this.beginY + this.period * HEIGHT * 0.015 * C + HEIGHT * 0.08 * dT;
再順便提醒一下,最右側dT所負責的參數,就是動畫的線性前進方向,較容易被肉眼觀察!
當我們如上述代碼設置,就會使畫面更加生動,每一個彷彿都是獨立的個體,有著自己的運動軌跡,很難將兩三個物件聯想在一起,不過作為整體來看,還是能稍微看出整個動畫的走向,正往斜右下掉落,能夠良好的表達當前的意境,彷彿真的隨風飄落一般。
除了上述的作法,還可以考量到在角速度不變的情況下,增減整體的位移,設計兩個隨機數:
this.scaleX = 0.5 + Math.random() * 1;
this.scaleY = 0.5 + Math.random() * 1;
用來縮放XY的位移,使得有些走得更長,有些走的更短:
let x = this.scaleX * (this.period * WIDTH * 0.04 * A + WIDTH * 0.02 * dT);
let y = this.scaleY * (this.period * HEIGHT * 0.02 * C + HEIGHT * 0.06 * dT);
this.pointX = this.beginX + x;
this.pointY = this.beginY + y;
其實混亂概念上也就是遠近效果,可以搭配物件大小或Z軸作為參考標準,就不會顯得如此混亂
與上面的多樣相比,較難感受到隨風飄落的意境,更像是有更多不確定因素,是一個混亂的系統,即便還是能感受到物件來回擺動,然而物件的移動總是不如預期,似乎總會差一些、差一點,讓人覺得整體不和諧,各個都在搗亂的樣子,適合用於困難的關卡,增加挑戰性和挫折感。
這是一個很主觀的定義,主要是對於掌控感下去作討論,我認為設計遊戲,無非就是思考:如何讓使用者感受到他能主宰整個遊戲世界,享受無邊無際的自由,強調回饋感這件事,是一個很值得摸索的設計,假如我們用在落葉掉落之時,那是否使用者就主宰了這個小世界,能隨著滑鼠的移動來改變動畫的行進,那是否,也掌控了風神呢?
採用的就是第二章用的滑鼠跟隨機制,參數設哪個沒有限制,看想研究哪個就設那個,該範例設置的是旋轉角速度:
function MouseAnime(){
myMouse.NextFrame();
animeList.forEach(obj => {
obj.rotateOmega = myMouse.pointX * 40 / obj.period / 180 * Math.PI;
if(mode == 'Free'){
obj.scaleX = 1 + myMouse.pointX/2;
obj.scaleY = 1 + myMouse.pointY/2;
}
})
}
不過要注意,每次滑鼠改變都會刷新,因此這種方法不能直接用於隨機數,比方說若想測試period,就得把一開始的隨機數存起來另外放,因此需要兩個變數。